package com.jonlandrum.collections.BinarySearchTree;

import org.junit.Test;

import static org.junit.Assert.*;

public class LinkedBinarySearchNodeTest {
    @Test
    public void testEmptyConstructor() {
        LinkedBinarySearchNode node = new LinkedBinarySearchNode<>();
        assertEquals(null, node.getData());
    }

    @Test
    public void testDataConstructor() {
        LinkedBinarySearchNode node = new LinkedBinarySearchNode<>("test");
        assertEquals("test", node.getData());
    }

    @Test
    public void testGetData_DataIsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>();
        assertEquals(null, node.getData());
    }

    @Test
    public void testGetData_DataIsNotNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        assertEquals("test", node.getData());
    }

    @Test
    public void testGetParent_ParentIsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        assertEquals(null, node.getParent());
    }

    @Test
    public void testGetParent_ParentIsNotNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        LinkedBinarySearchNode<String> parent = new LinkedBinarySearchNode<>("test");
        node.setParent(parent);
        assertEquals(parent, node.getParent());
    }

    @Test
    public void testGetLeft_LeftIsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        assertEquals(null, node.getLeft());
    }

    @Test
    public void testGetLeft_LeftIsNotNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        LinkedBinarySearchNode<String> left = new LinkedBinarySearchNode<>("test");
        node.setLeft(left);
        assertEquals(left, node.getLeft());
    }

    @Test
    public void testGetRight_RightIsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        assertEquals(null, node.getRight());
    }

    @Test
    public void testGetRight_RightIsNotNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        LinkedBinarySearchNode<String> right = new LinkedBinarySearchNode<>("test");
        node.setRight(right);
        assertEquals(right, node.getRight());
    }

    @Test
    public void testGetSuccessor_TargetHasLeftChild() {
        LinkedBinarySearchNode<Integer> node1 = new LinkedBinarySearchNode<>(1);
        LinkedBinarySearchNode<Integer> node2 = new LinkedBinarySearchNode<>(2);
        LinkedBinarySearchNode<Integer> node3 = new LinkedBinarySearchNode<>(3);
        LinkedBinarySearchNode<Integer> node4 = new LinkedBinarySearchNode<>(4);
        LinkedBinarySearchNode<Integer> node5 = new LinkedBinarySearchNode<>(5);
        node5.setLeft(node1);
        node1.setParent(node5);
        node1.setRight(node2);
        node2.setParent(node1);
        node2.setRight(node3);
        node3.setParent(node2);
        node3.setRight(node4);
        node4.setParent(node3);
        assertTrue(node5.getReplacement().toString().equals("4"));
    }

    @Test
    public void testGetSuccessor_TargetHasRightChild() {
        LinkedBinarySearchNode<Integer> node1 = new LinkedBinarySearchNode<>(1);
        LinkedBinarySearchNode<Integer> node2 = new LinkedBinarySearchNode<>(2);
        LinkedBinarySearchNode<Integer> node3 = new LinkedBinarySearchNode<>(3);
        LinkedBinarySearchNode<Integer> node4 = new LinkedBinarySearchNode<>(4);
        LinkedBinarySearchNode<Integer> node5 = new LinkedBinarySearchNode<>(5);
        node1.setRight(node5);
        node5.setParent(node1);
        node5.setLeft(node4);
        node4.setParent(node5);
        node4.setLeft(node3);
        node3.setParent(node4);
        node3.setLeft(node2);
        node2.setParent(node3);
        assertTrue(node1.getReplacement().toString().equals("2"));
    }

    @Test
    public void testGetSuccessor_TargetHasNoChildren() {
        LinkedBinarySearchNode<Integer> node1 = new LinkedBinarySearchNode<>(1);
        LinkedBinarySearchNode<Integer> node2 = new LinkedBinarySearchNode<>(2);
        LinkedBinarySearchNode<Integer> node3 = new LinkedBinarySearchNode<>(3);
        LinkedBinarySearchNode<Integer> node4 = new LinkedBinarySearchNode<>(4);
        LinkedBinarySearchNode<Integer> node5 = new LinkedBinarySearchNode<>(5);
        node1.setRight(node5);
        node5.setParent(node1);
        node5.setLeft(node4);
        node4.setParent(node5);
        node4.setLeft(node3);
        node3.setParent(node4);
        node3.setLeft(node2);
        node2.setParent(node3);
        assertTrue(node2.getReplacement().toString().equals(""));
    }

    @Test
    public void testSetData_DataIsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>();
        node.setData("test");
        assertEquals("test", node.getData());
    }

    @Test
    public void testSetData_DataIsNotNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        node.setData("success");
        assertEquals("success", node.getData());
    }

    @Test
    public void testSetParentAsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        LinkedBinarySearchNode<String> parent = new LinkedBinarySearchNode<>("test");
        node.setParent(parent);
        assertTrue(node.hasParent());
        node.setParent();
        assertFalse(node.hasParent());
    }

    @Test
    public void testSetParentAsNode() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        LinkedBinarySearchNode<String> parent = new LinkedBinarySearchNode<>("test");
        assertFalse(node.hasParent());
        node.setParent(parent);
        assertTrue(node.hasParent());
    }

    @Test
    public void testSetLeftAsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        LinkedBinarySearchNode<String> left = new LinkedBinarySearchNode<>("test");
        node.setLeft(left);
        assertTrue(node.hasLeft());
        node.setLeft();
        assertFalse(node.hasLeft());
    }

    @Test
    public void testSetLeftAsNode() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        LinkedBinarySearchNode<String> left = new LinkedBinarySearchNode<>("test");
        assertFalse(node.hasLeft());
        node.setLeft(left);
        assertTrue(node.hasLeft());
    }

    @Test
    public void testSetRightAsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        LinkedBinarySearchNode<String> right = new LinkedBinarySearchNode<>("test");
        node.setRight(right);
        assertTrue(node.hasRight());
        node.setRight();
        assertFalse(node.hasRight());
    }

    @Test
    public void testSetRightAsNode() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        LinkedBinarySearchNode<String> right = new LinkedBinarySearchNode<>("test");
        assertFalse(node.hasRight());
        node.setRight(right);
        assertTrue(node.hasRight());
    }

    @Test
    public void testHasData_DataIsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>();
        assertFalse(node.hasData());
    }

    @Test
    public void testHasData_DataIsNotNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        assertTrue(node.hasData());
    }

    @Test
    public void testHasParent() {
        LinkedBinarySearchNode<Double> node1 = new LinkedBinarySearchNode<>(1.1);
        LinkedBinarySearchNode<Double> node2 = new LinkedBinarySearchNode<>(1.2);
        assertFalse(node1.hasParent());
        node1.setParent(node2);
        assertTrue(node1.hasParent());
    }

    @Test
    public void testHasLeft() {
        LinkedBinarySearchNode<Double> node1 = new LinkedBinarySearchNode<>(1.1);
        LinkedBinarySearchNode<Double> node2 = new LinkedBinarySearchNode<>(1.2);
        assertFalse(node1.hasLeft());
        node1.setLeft(node2);
        assertTrue(node1.hasLeft());
    }

    @Test
    public void testHasRight() {
        LinkedBinarySearchNode<Double> node1 = new LinkedBinarySearchNode<>(1.1);
        LinkedBinarySearchNode<Double> node2 = new LinkedBinarySearchNode<>(1.2);
        assertFalse(node1.hasRight());
        node1.setRight(node2);
        assertTrue(node1.hasRight());
    }

    @Test
    public void testHasChild_NoChildrenEverAssigned() {
        LinkedBinarySearchNode<Character> parent = new LinkedBinarySearchNode<>('d');
        assertFalse(parent.hasChild());
    }

    @Test
    public void testHasChild_LeftChildAssigned() {
        LinkedBinarySearchNode<Character> parent = new LinkedBinarySearchNode<>('d');
        LinkedBinarySearchNode<Character> child = new LinkedBinarySearchNode<>('a');
        parent.setLeft(child);
        assertTrue(parent.hasChild());
    }

    @Test
    public void testHasChild_RightChildAssigned() {
        LinkedBinarySearchNode<Character> parent = new LinkedBinarySearchNode<>('d');
        LinkedBinarySearchNode<Character> child = new LinkedBinarySearchNode<>('a');
        parent.setRight(child);
        assertTrue(parent.hasChild());
    }

    @Test
    public void testHasChild_BothChildrenAssigned() {
        LinkedBinarySearchNode<Character> parent = new LinkedBinarySearchNode<>('d');
        LinkedBinarySearchNode<Character> child1 = new LinkedBinarySearchNode<>('a');
        LinkedBinarySearchNode<Character> child2 = new LinkedBinarySearchNode<>('g');
        parent.setLeft(child1);
        parent.setRight(child2);
        assertTrue(parent.hasChild());
    }

    @Test
    public void testHasChild_ChildDeleted() {
        LinkedBinarySearchNode<Character> parent = new LinkedBinarySearchNode<>('d');
        LinkedBinarySearchNode<Character> child = new LinkedBinarySearchNode<>('a');
        parent.setLeft(child);
        parent.setLeft();
        assertFalse(parent.hasChild());
    }

    @Test
    public void testIsLeft_ParentIsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("node");
        assertFalse(node.isLeft());
    }

    @Test
    public void testIsLeft_ParentIsNotNull_NodeIsLeftChild() {
        LinkedBinarySearchNode<String> child = new LinkedBinarySearchNode<>("child");
        LinkedBinarySearchNode<String> parent = new LinkedBinarySearchNode<>("parent");
        parent.setLeft(child);
        child.setParent(parent);
        assertTrue(child.isLeft());
    }

    @Test
    public void testIsLeft_ParentIsNotNull_NodeIsRightChild() {
        LinkedBinarySearchNode<String> child = new LinkedBinarySearchNode<>("child");
        LinkedBinarySearchNode<String> parent = new LinkedBinarySearchNode<>("parent");
        parent.setRight(child);
        child.setParent(parent);
        assertFalse(child.isLeft());
    }

    @Test
    public void testIsRight_ParentIsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("node");
        assertFalse(node.isRight());
    }

    @Test
    public void testIsRight_ParentIsNotNull_NodeIsRightChild() {
        LinkedBinarySearchNode<String> child = new LinkedBinarySearchNode<>("child");
        LinkedBinarySearchNode<String> parent = new LinkedBinarySearchNode<>("parent");
        parent.setRight(child);
        child.setParent(parent);
        assertTrue(child.isRight());
    }

    @Test
    public void testIsRight_ParentIsNotNull_NodeIsLeftChild() {
        LinkedBinarySearchNode<String> child = new LinkedBinarySearchNode<>("child");
        LinkedBinarySearchNode<String> parent = new LinkedBinarySearchNode<>("parent");
        parent.setLeft(child);
        child.setParent(parent);
        assertFalse(child.isRight());
    }

    @Test
    public void testToString_DataIsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>();
        assertEquals("", node.toString());
    }

    @Test
    public void testToString_DataIsNotNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        assertEquals("test", node.toString());
    }

    @Test(expected = NullPointerException.class)
    public void testCompareTo_TargetIsNull() {
        LinkedBinarySearchNode<String> node = new LinkedBinarySearchNode<>("test");
        node.compareTo(new LinkedBinarySearchNode<String>());
    }

    @Test
    public void testCompareTo_TargetIsData() {
        LinkedBinarySearchNode<Integer> node = new LinkedBinarySearchNode<>(1);
        assertEquals(-1, node.compareTo(new LinkedBinarySearchNode<>(2)));
    }

    @Test
    public void testCompareTo_TargetIsNode() {
        LinkedBinarySearchNode<Integer> node = new LinkedBinarySearchNode<>(1);
        assertEquals(-1, node.compareTo(new LinkedBinarySearchNode<>(2)));
    }
}
